#!/usr/bin/perl
# 2014/03/12 changed for human data treating
# 2012/11/07 Sorting map file

use strict;
use warnings;
use IO::File;
use Getopt::Std;
use File::Basename;
use Carp qw(croak);
$| = 0;

if(@ARGV != 4 or $ARGV[0] eq '--help'){
	die "Usage : $0 -i [map file] -o [sorted outfile]\n";
}


my $LINE_PER_FILES = 1000000;

#---------------------------------------
# map format
#---------------------------------------
# id chr1 loc1 direction1 quality1 hind1 hind_loc1 chr2 loc2 direction2 quality2 hind2 hind_loc2 type(unique or repeat) number(alignable locations) locations

my %opt;
getopts("i:o:", \%opt);
my $FILE_map = $opt{i};
my $FILE_result = $opt{o};
my ($name, $dir, $ext) = &fileparse($FILE_map, '\..*');
my $FILE_tmp = 'tmp_merge_' . $name;

my @tmpfiles;
my %data;
my $count = 0;

#---------------------------------------
# collect data
#---------------------------------------
my $fh_map = IO::File->new($FILE_map) or die "cannot open $FILE_map: $!";
while($_ = $fh_map->getline()){
	s/\r?\n//;
	my ($id, $chr1, $loc1, $direction1, $mapQ1, $hinID1, $hinLoc1, $chr2, $loc2, $direction2, $mapQ2, $hinID2, $hinLoc2, $type, $num, $locations) = split /\t/;

	if($chr1 eq 'NA' or $chr2 eq 'NA'){
		next;
	}

	my $value1 = &chr2num($chr1) + $loc1;
	my $value2 = &chr2num($chr2) + $loc2;
	my $value = $value1 * 100000000000 + $value2;

	my $key = "$value\t$_";
	$data{$key} = $value;
	$count++;

	if($count > $LINE_PER_FILES){
		my $tmpFile = 'tmp_' . $name . '_' . @tmpfiles;
		push @tmpfiles, $tmpFile;
		&status("output $tmpFile");
		my $fh_tmp = IO::File->new($tmpFile, 'w') or die "cannot write $tmpFile: $!";
		foreach my $k(sort {$data{$a} <=> $data{$b} } keys %data){
			$fh_tmp->print("$k\n");
		}
		$fh_tmp->close();
		%data = ();
		$count = 0;
	}
}
$fh_map->close();
# remaining data
my $fh_result = IO::File->new($FILE_result, 'w') or die "cannot write $FILE_result: $!";
foreach my $k(sort {$data{$a} <=> $data{$b} } keys %data){
	$fh_result->print("$k\n");
}
$fh_result->close();


#---------------------------------------
# sorting
#---------------------------------------
foreach my $tmpFile(@tmpfiles){
    &status("read $tmpFile");
	my $fh_result = IO::File->new($FILE_result) or die "cannot open $FILE_result: $!";
	my $fh_tmp = IO::File->new($tmpFile) or die "cannot open $tmpFile: $!";
	my $fh_out = IO::File->new($FILE_tmp, 'w') or die "cannot write $FILE_tmp: $!";

	my $s1 = $fh_result->getline();
	my $s2 = $fh_tmp->getline();

	while($s1 && $s2){
		my ($n1, @other1) = split /\t/, $s1;
		my ($n2, @other2) = split /\t/, $s2;
		if($n1 < $n2){
			$fh_out->print("$s1");
			$s1 = $fh_result->getline();
		}elsif($n1 > $n2){
			$fh_out->print("$s2");
			$s2 = $fh_tmp->getline();
		}else{
			$fh_out->print("$s1");
			$fh_out->print("$s2");
			$s1 = $fh_result->getline();
			$s2 = $fh_tmp->getline();
		}
	}
	while($s1){
		$fh_out->print("$s1");
		$s1 = $fh_result->getline();
	}
	while($s2){
		$fh_out->print("$s2");
		$s2 = $fh_tmp->getline();
	}
	$fh_out->close();
	$fh_result->close();
	$fh_tmp->close();

	rename $FILE_tmp, $FILE_result or die "cannot rename file: $!";
	unlink $tmpFile;
}


#---------------------------------------
# remove the number
#---------------------------------------
{
	my $fh_out = IO::File->new($FILE_tmp, 'w') or die "cannot write tmp: $!";
	my $fh_in = IO::File->new($FILE_result) or die "cannot open $FILE_result: $!";

	while($_ = $fh_in->getline()){
		my ($n, $id, $chr1, $loc1, $direction1, $mapQ1, $hinID1, $hinLoc1, $chr2, $loc2, $direction2, $mapQ2, $hinID2, $hinLoc2, $type, $num, $locations) = split /\t/;
		my $key = join("\t", $id, $chr1, $loc1, $direction1, $mapQ1, $hinID1, $hinLoc1, $chr2, $loc2, $direction2, $mapQ2, $hinID2, $hinLoc2, $type, $num, $locations);
		$fh_out->print("$key");
	}
	$fh_in->close();
	$fh_out->close();
	rename $FILE_tmp, $FILE_result or die "cannot rename file: $!";
}

sub chr2num{
	my ($chr) = @_;
	if($chr =~ /chr(\w+)/){
		my $num = $1;
		my $value = 0;
		if($num eq 'X'){
			$value = 23 * 1000000000;
		}elsif($num eq 'Y'){
			$value = 24 * 1000000000;
		}else{
			$value = $num * 1000000000;
		}
		return $value;
	}else{
		return 25 * 1000000000;
	}
}

sub status{
	my ($message) = @_;
	my $time = &time();
	print "[$time] $message ... \n";
}


sub time{
	my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
	my $time = sprintf ("%d/%0d %02d:%02d",$mon+1, $mday, $hour, $min);
	return $time;
}
